logo of company

Lumo: a clean Quarto template


Quarto is a stunning tool. It transforms your R or Python code in a very clean report that includes code, charts, explanation and everything else you would like to include.
Lumo is a quarto template. It slightly modifies the default appearance of a Quarto document, to make it even more shiny, and fit your brand.
This document demoes how a document made with lumo looks like, list its main features and explain how to use it in 3 minutes.

Author: Holtz Yan

Date: September 10, 2024

Introduction

Quarto is probably my favorite tool in the R/Python universe. Transforming your code and thoughts into a stunning report in one click always blows my mind.

Even if the default appearance looks good, there are a few tweaks I always like to apply to push the report to the next level.

Btw, you can learn how to master Quarto thanks to my online course: Productive R Workflow

This document aims at showcasing how a quarto document made with the lumo format looks like.

Code
library(tidyverse) 
library(hrbrthemes)
library(viridis)
library(ggiraph)
library(patchwork) 
library(sf)
1
this package provides my favorite ggplot2 theme: theme_ipsum()
2
because I was too lazy to find something better in the R Color Finder!

By the way, you should open the code chunk that is folded above. ⬆️ There is a little stunning surprise on its right hand side.

Everybody loves map ❤️

Don’t forget that you can add full width content, which can be very useful for instance for a nice interactive map made with leaflet.

Code
# Load the library.
library(leaflet)

# Make a map
leaflet() %>%
  addTiles() %>% # Add default OpenStreetMap map tiles
  addMarkers(lng = 174.768, lat = -36.852, popup = "The birthplace of R")

Connecting graphs

All right, many people know how to create interactive graphs with plotly. But did you know that you can connect graphs together thanks to ggiraph? And using a syntax pretty close from ggplot2?

Pretty close from dark magic isn’t.

Code
# Read the full world map
world_sf <- read_sf("https://raw.githubusercontent.com/holtzy/R-graph-gallery/master/DATA/world.geojson")
world_sf <- world_sf %>%
  filter(!name %in% c("Antarctica", "Greenland"))

# Create a sample dataset
happiness_data <- data.frame(
  Country = c(
    "France", "Germany", "United Kingdom",
    "Japan", "China", "Vietnam",
    "United States of America", "Canada", "Mexico"
  ),
  Continent = c(
    "Europe", "Europe", "Europe",
    "Asia", "Asia", "Asia",
    "North America", "North America", "North America"
  ),
  Happiness_Score = rnorm(mean = 30, sd = 20, n = 9),
  GDP_per_capita = rnorm(mean = 30, sd = 20, n = 9),
  Social_support = rnorm(mean = 30, sd = 20, n = 9),
  Healthy_life_expectancy = rnorm(mean = 30, sd = 20, n = 9)
)

# Join the happiness data with the full world map
world_sf <- world_sf %>%
  left_join(happiness_data, by = c("name" = "Country"))


# Create the first chart (Scatter plot)
p1 <- ggplot(world_sf, aes(
  GDP_per_capita,
  Happiness_Score,
  tooltip = name,
  data_id = Continent,
  color = Continent
)) +
  geom_point_interactive(data = filter(world_sf, !is.na(Happiness_Score)), size = 4) +
  theme_minimal() +
  theme(
    axis.title.x = element_blank(),
    axis.title.y = element_blank(),
    legend.position = "none"
  )

# Create the second chart (Bar plot)
p2 <- ggplot(world_sf, aes(
  x = reorder(name, Happiness_Score),
  y = Happiness_Score,
  tooltip = name,
  data_id = Continent,
  fill = Continent
)) +
  geom_col_interactive(data = filter(world_sf, !is.na(Happiness_Score))) +
  coord_flip() +
  theme_minimal() +
  theme(
    axis.title.x = element_blank(),
    axis.title.y = element_blank(),
    legend.position = "none"
  )

# Create the third chart (choropleth)
p3 <- ggplot() +
  geom_sf(data = world_sf, fill = "lightgrey", color = "lightgrey") +
  geom_sf_interactive(
    data = filter(world_sf, !is.na(Happiness_Score)),
    aes(fill = Continent, tooltip = name, data_id = Continent)
  ) +
  coord_sf(crs = st_crs(3857)) +
  theme_void() +
  theme(
    axis.title.x = element_blank(),
    axis.title.y = element_blank(),
    legend.position = "none"
  )

# Combine the plots
combined_plot <- (p1 + p2) / p3 + plot_layout(heights = c(1, 2))

# Create the interactive plot
interactive_plot <- girafe(ggobj = combined_plot)
interactive_plot <- girafe_options(
  interactive_plot,
  opts_hover(css = "fill:red;stroke:black;")
)

interactive_plot

Figure: three graphs connected thanks to ggiraph

Interactive table

It is very easy to insert an interactive table in your document thanks to the DT package. The output allows to filter rows, search for something and sort using a specific columns!

Install the library with install.packages("DT"). Then, just pass a dataframe to the datatable() function to get a stunning interactive output!

Code
library(DT)
data(iris)

# Make a table
datatable(iris, filter = "top")

A grey section

It’s always good to have a grey section. Makes the document breath a bit.

Let’s use this space to render a little equation:

\[ x = \frac{-b \pm \sqrt{b^2 - 4ac}}{2a} \]

More Information

You can learn more about controlling the appearance of HTML output here: https://quarto.org/docs/output-formats/html-basics.html

Quarto tricks

If you have several plots to make, each targeting something special in your dataset, you should consider using pills for that!

Session Info

When you make a Quarto doc, it is a good practice to include information about your working environment. This is straightforward, you just have to call the sessionInfo() info and all your R and package versions will be printed. This is a huge boost for reproducibility.

Code
sessionInfo()
R version 4.4.0 (2024-04-24)
Platform: aarch64-apple-darwin20
Running under: macOS Sonoma 14.4.1

Matrix products: default
BLAS:   /Library/Frameworks/R.framework/Versions/4.4-arm64/Resources/lib/libRblas.0.dylib 
LAPACK: /Library/Frameworks/R.framework/Versions/4.4-arm64/Resources/lib/libRlapack.dylib;  LAPACK version 3.12.0

locale:
[1] en_US.UTF-8/en_US.UTF-8/en_US.UTF-8/C/en_US.UTF-8/en_US.UTF-8

time zone: Europe/Paris
tzcode source: internal

attached base packages:
[1] stats     graphics  grDevices utils     datasets  methods   base     

other attached packages:
 [1] DT_0.33           leaflet_2.2.2     sf_1.0-16         patchwork_1.2.0  
 [5] ggiraph_0.8.10    viridis_0.6.5     viridisLite_0.4.2 hrbrthemes_0.8.7 
 [9] lubridate_1.9.3   forcats_1.0.0     stringr_1.5.1     dplyr_1.1.4      
[13] purrr_1.0.2       readr_2.1.5       tidyr_1.3.1       tibble_3.2.1     
[17] ggplot2_3.5.1     tidyverse_2.0.0  

loaded via a namespace (and not attached):
 [1] gtable_0.3.5            bslib_0.7.0             xfun_0.43              
 [4] htmlwidgets_1.6.4       tzdb_0.4.0              crosstalk_1.2.1        
 [7] vctrs_0.6.5             tools_4.4.0             generics_0.1.3         
[10] curl_5.2.1              proxy_0.4-27            fansi_1.0.6            
[13] pkgconfig_2.0.3         KernSmooth_2.23-22      uuid_1.2-0             
[16] lifecycle_1.0.4         farver_2.1.1            compiler_4.4.0         
[19] munsell_0.5.1           httpuv_1.6.15           fontquiver_0.2.1       
[22] fontLiberation_0.1.0    sass_0.4.9              class_7.3-22           
[25] htmltools_0.5.8.1       yaml_2.3.8              Rttf2pt1_1.3.12        
[28] jquerylib_0.1.4         pillar_1.9.0            later_1.3.2            
[31] crayon_1.5.2            extrafontdb_1.0         gfonts_0.2.0           
[34] classInt_0.4-10         cachem_1.0.8            mime_0.12              
[37] fontBitstreamVera_0.1.1 tidyselect_1.2.1        digest_0.6.35          
[40] stringi_1.8.4           labeling_0.4.3          extrafont_0.19         
[43] fastmap_1.1.1           grid_4.4.0              colorspace_2.1-0       
[46] cli_3.6.2               magrittr_2.0.3          crul_1.4.2             
[49] utf8_1.2.4              e1071_1.7-14            withr_3.0.0            
[52] gdtools_0.3.7           scales_1.3.0            promises_1.3.0         
[55] timechange_0.3.0        rmarkdown_2.26          gridExtra_2.3          
[58] hms_1.1.3               shiny_1.8.1.1           evaluate_0.23          
[61] knitr_1.46              rlang_1.1.3             Rcpp_1.0.12            
[64] DBI_1.2.2               xtable_1.8-4            glue_1.7.0             
[67] httpcode_0.3.0          rstudioapi_0.16.0       jsonlite_1.8.8         
[70] R6_2.5.1                units_0.8-5             systemfonts_1.0.6